package vn.vfriends.vbox.provider;

import javax.ws.rs.client.Client;
import javax.ws.rs.client.ClientBuilder;
import javax.ws.rs.client.Entity;
import javax.ws.rs.client.WebTarget;
import javax.ws.rs.core.Form;
import javax.ws.rs.core.MediaType;
import javax.xml.bind.annotation.XmlRootElement;
import org.scribe.utils.OAuthEncoder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import vn.vfriends.vbox.util.ProviderUtil;

/**
 *
 * @author tuancn
 */
public class GoogleProvider implements StorageProvider {
    
    private static final Logger logger = LoggerFactory.getLogger(GoogleProvider.class);
    
    private static final String DRIVE_SCOPE = "https://www.googleapis.com/auth/drive";
    
    private static final String EMAIL_SCOPE = "https://www.googleapis.com/auth/userinfo.email";
    
    private static final String API_KEY = ProviderUtil.getProperties().getProperty("GOOGLE_DRIVE_API_KEY");
    
    private static final String API_SECRET = ProviderUtil.getProperties().getProperty("GOOGLE_DRIVE_API_SECRET");
    
    private static final String CALLBACK_URL = ProviderUtil.getProperties().getProperty("GOOGLE_DRIVE_CALLBACK_URL");
    
    private static final String AUTHORIZATION_URL = "https://accounts.google.com/o/oauth2/auth?state=vbox&client_id=%s&redirect_uri=%s&scope=%s&response_type=code&access_type=offline";
    
    private String accessToken;
    
    private String refreshToken;
    
    private long expiresIn;
    
    private String ownId;
    
    private String name;
    
    public GoogleProvider() {
    }
    
    @Override
    public String getAuthorizationUrl() {
        return String.format(AUTHORIZATION_URL, API_KEY, OAuthEncoder.encode(CALLBACK_URL), EMAIL_SCOPE + " " + DRIVE_SCOPE);
    }
    
    @Override
    public void init(String code) {
        Client client = ClientBuilder.newClient();
        WebTarget target = client.target("https://accounts.google.com/o/oauth2/token");
        
        Form form = new Form();
        form.param("code", code);
        form.param("grant_type", "authorization_code");
        form.param("client_id", API_KEY);
        form.param("client_secret", API_SECRET);
        form.param("redirect_uri", CALLBACK_URL);
        
        GoogleTokenResponse res = target.request(MediaType.APPLICATION_JSON_TYPE)
                .post(Entity.entity(form, MediaType.APPLICATION_FORM_URLENCODED_TYPE), GoogleTokenResponse.class);
        this.accessToken = res.getAccess_token();
        this.refreshToken = res.getRefresh_token();
        this.expiresIn = res.getExpires_in();
        
        target = client.target("https://www.googleapis.com/oauth2/v2/userinfo").queryParam("access_token", this.accessToken);
        GoogleProfile profile = target.request().get(GoogleProfile.class);
        this.ownId = profile.getId();
        this.name = profile.getName();
    }
    
    
    
    @Override
    public String getOwnId() {
        return this.ownId;
    }

    @Override
    public String getName() {
        return name;
    }

    @Override
    public String getAccessToken() {
        return accessToken;
    }
    
    @Override
    public String getRefreshToken() {
        return this.refreshToken;
    }
    
    @Override
    public long getExpiresIn() {
        return this.expiresIn;
    }
}

@XmlRootElement
class GoogleTokenResponse {

    private String access_token;

    private String refresh_token;

    private long expires_in;

    public String getAccess_token() {
        return access_token;
    }

    public void setAccess_token(String access_token) {
        this.access_token = access_token;
    }

    public String getRefresh_token() {
        return refresh_token;
    }

    public void setRefresh_token(String refresh_token) {
        this.refresh_token = refresh_token;
    }

    public long getExpires_in() {
        return expires_in;
    }

    public void setExpires_in(long expires_in) {
        this.expires_in = expires_in;
    }
}

@XmlRootElement
class GoogleProfile {

    private String name;
    
    private String id;

    public String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}
